
package org.apache.osgimaker.analyse.algorithm.dependency;

import java.util.HashSet;
import java.util.Set;

import org.apache.osgimaker.analyse.algorithm.graph.NameAttributes;
import org.apache.osgimaker.analyse.algorithm.graph.Vertex;
import org.apache.osgimaker.analyse.algorithm.graph.VertexCondition;
import org.apache.osgimaker.analyse.algorithm.util.StringPattern;



public class DependencyPathsRenderer
{
  private static final String INDENT = "  ";
  private final Vertex[] _graph;
  private final VertexCondition _startSetCondition;
  private final VertexCondition _finalSetCondition;
  private final Set<Vertex> _vertices = new HashSet<Vertex>();
  
  public DependencyPathsRenderer(Vertex[] graph, 
                                 StringPattern startSetPattern, 
                                 StringPattern finalSetPattern)
  {
    this(graph, new PatternVertexCondition(startSetPattern), 
                new PatternVertexCondition(finalSetPattern));
  }
  
  public DependencyPathsRenderer(Vertex[] graph, 
                                 VertexCondition startSetCondition,
                                 VertexCondition finalSetCondition)
  {
    _graph = graph;
    _startSetCondition = startSetCondition;
    _finalSetCondition = finalSetCondition;
    for (int i = 0; i < graph.length; i++)
    {
      _vertices.add(graph[i]);
    }
  }
  
  public String renderGraph(final String lineStart)
  {
    final StringBuffer buffer = new StringBuffer();
    DependencyPathRenderer renderer = new DependencyPathRenderer()
      {
        String _start = '\n' + lineStart;
        private int _indentation;
    
        public void increaseIndentation()
        {
          _indentation++;
        }
    
        public void add(String nodeName)
        {
          buffer.append(_start);
          for (int i = 0; i < _indentation; i++)
          {
            buffer.append(INDENT);
          }
          if (_indentation > 0)
          {
            buffer.append("-> ");
          }
          buffer.append(nodeName);
        }
        
        public void decreaseIndentation()
        {
          _indentation--;
        }
    
      };
    renderGraph(renderer);
    
    return new String(buffer);
  }
  
  public void renderGraph(DependencyPathRenderer renderer)
  {
    Set<Vertex> visitedVertices = new HashSet<Vertex>();
    for (int i = 0; i < _graph.length; i++)
    {
      Vertex vertex = _graph[i];
      if (_startSetCondition.isFulfilled(vertex))
      {
        renderer.add(getNameOf(vertex));
        renderPaths(renderer, vertex, visitedVertices);
      }
    }
  }

  private void renderPaths(DependencyPathRenderer renderer, Vertex vertex, 
                           Set<Vertex> visitedVertices)
  {
    visitedVertices.add(vertex);
    renderer.increaseIndentation();
    for (int i = 0, n = vertex.getNumberOfOutgoingArcs(); i < n; i++)
    {
      Vertex headVertex = vertex.getHeadVertex(i);
      if (_vertices.contains(headVertex)
          && !_startSetCondition.isFulfilled(headVertex))
      {
        renderer.add(getNameOf(headVertex));
        if (!_finalSetCondition.isFulfilled(headVertex) 
            && !visitedVertices.contains(headVertex))
        {
          renderPaths(renderer, headVertex, visitedVertices);
        }
      }
    }
    renderer.decreaseIndentation();
  }

  private String getNameOf(Vertex vertex)
  {
    return ((NameAttributes) vertex.getAttributes()).getName();
  }
}
